package com.lnsystem.service.impl;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.log4j.Logger;
import org.scribe.builder.ServiceBuilder;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.oauth.OAuthService;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lnsystem.constants.TKConstants;
import com.lnsystem.model.Stock;
import com.lnsystem.model.StockDailyData;
import com.lnsystem.model.tk.quotehistorical.Data;
import com.lnsystem.model.tk.quotehistorical.TKHistoricalQuotes;
import com.lnsystem.model.tk.quotemultiple.TKQuotes;
import com.lnsystem.model.tk.quotesingle.Quote;
import com.lnsystem.model.tk.quotesingle.Quotes;
import com.lnsystem.model.tk.quotesingle.TKQuote;
import com.lnsystem.service.QuoteService;

public class QuoteServiceTKImpl implements QuoteService {

	private static Logger log = Logger.getLogger(QuoteServiceTKImpl.class);
	
	private OAuthService service;
	private Token accessToken;
	private SimpleDateFormat format = new SimpleDateFormat("y-M-d");
	
	//TODO - change this later to be injected.
	private ObjectMapper mapper = new ObjectMapper(); 
	
	// TODO change this later to be injected.
	public void initializeOAuth(){
		service = new ServiceBuilder()
        .provider(TradeKingApi.class)
        .apiKey(TKConstants.CONSUMER_KEY)
        .apiSecret(TKConstants.CONSUMER_SECRET)
        .build();
		
		accessToken = new Token(TKConstants.OAUTH_TOKEN, TKConstants.OAUTH_TOKEN_SECRET);
	}
	
	public QuoteServiceTKImpl(){
		if(service == null){
			initializeOAuth();
		}
	}
	/*
	 * {@inheritDoc}
	 */
	public StockDailyData getStockData(String symbol) {

		StockDailyData data = new StockDailyData();

		//make sure we send only one symbol in the OAuth request.
		String[] s = symbol.split(",");
		
		if(service != null){
			OAuthRequest request = new OAuthRequest(Verb.GET, TKConstants.QUOTES_URL+s[0]);
			service.signRequest(accessToken, request);
			Response response = request.send();
			String quoteAsJSONString = response.getBody();
			
			log.debug("Response from TK REST service: "+quoteAsJSONString);
			
			try {
				TKQuote tkQuote = mapper.readValue(quoteAsJSONString, TKQuote.class);
				Quotes quotes = tkQuote.getResponse().getQuotes();
				Quote quote = quotes.getQuote();
				
				//TODO - add more code here to fill up data..
				//TODO add code to check for nulls.
				//data.setIndex(quote.getExch());
				//data.setName(quote.getName());
				data.setSymbol(quote.getSymbol());
				data.setOpen(Double.parseDouble(quote.getOpn()));
				data.setHigh(Double.parseDouble(quote.getHi()));
				data.setLow(Double.parseDouble(quote.getLo()));
				data.setClose(Double.parseDouble(quote.getLast()));
				data.setVolume(Double.parseDouble(quote.getVl()));
				data.setDate(format.parse(quote.getDate()));

				
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return data;
	}

	/*
	 * {@inheritDoc}
	 */
	public List<StockDailyData> getStockData(List<String> symbols) {
		
		List<StockDailyData> stockDataList = new ArrayList<StockDailyData>();
		String commaSeperatedList = "";
		
		// form a comma separated list to be sent in the URL.
		if(symbols!=null && symbols.size()>0){
			commaSeperatedList = StringUtils.join(symbols,",");
		}
		
		if(service != null){
			OAuthRequest request = new OAuthRequest(Verb.GET, TKConstants.QUOTES_URL+commaSeperatedList);
			service.signRequest(accessToken, request);
			Response response = request.send();
			String quoteAsJSONString = response.getBody();
			
			try {
				
				TKQuotes tkQuotes = mapper.readValue(quoteAsJSONString, TKQuotes.class);
				com.lnsystem.model.tk.quotemultiple.Quotes quotes = tkQuotes.getResponse().getQuotes();
				List<com.lnsystem.model.tk.quotemultiple.Quote>quote = quotes.getQuote();
				
				for(com.lnsystem.model.tk.quotemultiple.Quote q : quote ){
					StockDailyData stock = new StockDailyData();
					//TODO add implementation here..
					//stock.setIndex(q.getExch());
					//stock.setName(q.getName());
					//stock.setSymbol(q.getSymbol());
					stockDataList.add(stock);
				}

			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		return stockDataList;
	}
	
	/*
	 * {@inheritDoc}
	 */
	public List<StockDailyData> getHistoricalQuotes(String symbol, String startDate, String endDate, String interval){
		
		//TODO need to change it to stockdaily,weekly etc..
		List<StockDailyData> historicalQuotes = new ArrayList<StockDailyData>();
		List<Data> dataList = new ArrayList<Data>();
		String quoteAsJSONString = "";
		//make sure we send only the first symbol in the OAuth request, create a string array s[] and send s[0].
		String[] s = symbol.split(",");
		String historicalQuotesURL = String.format(TKConstants.HISTORICAL_QUOTES_URL, s[0],startDate,endDate,interval);
		
		if(service != null){
			
			try {
			OAuthRequest request = new OAuthRequest(Verb.GET, historicalQuotesURL);
			service.signRequest(accessToken, request);
			Response response = request.send();
			
			//The symbol ESBA  always returned "Internal Server Error" at response.getBody()
			// Modified code to handle it and continue
			
				quoteAsJSONString = response.getBody();
			} catch(IllegalArgumentException iae) {
				log.error("Error occured while reading the getHistoricalQuote() response for symbol:"+symbol+", error details: "+iae.getLocalizedMessage());
				return Collections.<StockDailyData>emptyList();
			} catch(Exception e) {
				log.error("I/O Error occured while getting the getHistoricalQuote() response for symbol:"+symbol+", error details: "+e.getLocalizedMessage());
				return Collections.<StockDailyData>emptyList();	
			}
			
			
			log.debug("Response from TK historical REST service: "+quoteAsJSONString);
			
			if(quoteAsJSONString.indexOf("Invalid symbol")>=0){ // invalid symbol
				log.error("Invalid symbol found in the list: "+symbol);
				return Collections.<StockDailyData>emptyList();
			}
			
			try {
				TKHistoricalQuotes tkHistoricalQuotes = mapper.readValue(quoteAsJSONString, TKHistoricalQuotes.class);
				dataList = tkHistoricalQuotes.getResponse().getTimeseries().getSeries().getData();
				
				for(Data d : dataList){
					StockDailyData dailyData = new StockDailyData();
					
					
					if(d.getClose()!=null){
						dailyData.setClose(Double.parseDouble(d.getClose()));
					} else {
						dailyData.setClose(0);
					}
					
					if(d.getOpen()!=null){
						dailyData.setOpen(Double.parseDouble(d.getOpen()));
					} else {
						dailyData.setOpen(0);
					}
					
					if(d.getHigh()!=null){
						dailyData.setHigh(Double.parseDouble(d.getHigh()));
					} else {
						dailyData.setHigh(0);
					}
					
					if(d.getLow()!=null){
						dailyData.setLow(Double.parseDouble(d.getLow()));
					} else {
						dailyData.setLow(0);
					}
					
					dailyData.setSymbol(tkHistoricalQuotes.getResponse().getTimeseries().getSymbol());
					
					if(d.getVolume()!=null){
						dailyData.setVolume(Double.parseDouble(d.getVolume()));
					} else {
						dailyData.setVolume(0);
					}
					
					if(d.getDate()!=null){
						dailyData.setDate(format.parse(d.getDate()));
					} else {
						dailyData.setDate(format.parse("1000-01-01"));
					}
					
					historicalQuotes.add(dailyData);
				}
				
			} catch (Exception e) {
				log.fatal("Exception occured: "+ExceptionUtils.getStackTrace(e));
				e.printStackTrace();
				return Collections.<StockDailyData>emptyList();
			}
		}		
		return historicalQuotes;
	}
	
	public static void main(String s[]){
		
		QuoteServiceTKImpl q = new QuoteServiceTKImpl();
		/*
		Stock stock  = q.getQuote("IBM,GOOG");
		log.info(stock.toString());
		
		String[] symbols = {"IBM","GOOG","AAPL"};
		List<Stock> stocks = q.getQuote(Arrays.asList(symbols));
		for(Stock st : stocks){
			log.info(st.toString());
		}*/
		
		//StockDailyData stockDailyData = q.getStockData("IBM");
		//System.out.println(">>>> "+stockDailyData.getClose());
		
		
		//testing with the symbol: ESBA which always returned "Internal Server Error"
		// Modified code to handle it and continue
		String symbolsList[] = {"ESBA","ALXN","ANIK","AMZN"};
		for(String sym : symbolsList) {
			List<StockDailyData> historical = q.getHistoricalQuotes(sym, "2014-06-05", "2014-12-31", "daily");
			for(StockDailyData st : historical){
				log.info(st.toString());
			}
		}
		
		
		//q.testHistoricalURL();;

	}

	public void testHistoricalURL() {
		String URL= "https://api.tradeking.com/v1/market/historical/search.json?symbols=IBM&startdate=2014-01-01&interval=daily";//&enddate=2014-12-31&interval=daily";
		if(service!=null) {
			OAuthRequest request = new OAuthRequest(Verb.GET, URL);
			service.signRequest(accessToken, request);
			Response response = request.send();
			String quoteAsJSONString = response.getBody();
			System.out.println("Response: "+quoteAsJSONString);
		}
	}
		
}

